// 函数

function function_eg01() {
  // 命名方式
  function add(x: number, y: number): number {
    return x + y;
  }
  // 匿名函数
  let myAdd = function (x: number, y: number): number {
    return x + y;
  }

  // 书写完整函数类型
  let myAdd_new: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
  }

  // 函数类型包含两部分：参数类型和返回值类型。 当写出完整函数类型的时候，这两部分都是需要的。
  // 参数类型 可以自定义命名，只要参数类型是匹配的，那么就认为它是有效的函数类型，而不在乎参数名是否正确。
  // 返回值类型，需要在函数和返回值类型之前使用( =>)符号，即使函数没有任何返回值，也需要指定void。
  let my_add_new: (baseVal: number, increment: number) => number = function (x: number, y: number): number {
    return x + y;
  }
}

// 可选参数和默认参数
function function_eg02() {
  function buildName(fname: string, lname: string) {
    return fname + '-' + lname;
  }

  // let result1 = buildName("Bob");                  // error, too few parameters
  // let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
  // let result3 = buildName("Bob", "Adams");

  // 简短地说，传递给一个函数的参数个数必须与函数期望的参数个数一致。

  function buildName_new(fname: string, lname?: string) {
    if (lname) {
      return fname + '-' + lname;
    } else {
      return fname;
    }
  }

  // let result1 = buildName_new("Bob");  // works correctly now
  // let result2 = buildName_new("Bob", "Adams", "Sr.");  // error, too many parameters
  // let result3 = buildName_new("Bob", "Adams");  // ah, just right

  // 可选参数可以控制参数的可传可不传，不传就是undefined。
}

// 剩余参数
function function_eg03() {
  // 剩余参数会被当做个数不限的可选参数。
  function buildName(fname: string, ...restArgs: string[]) {
    return fname + '-' + restArgs.join('-');
  }

  let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

  console.log(employeeName)
}

// 函数重载
function function_eg04() {
  let suits = ["hearts", "spades", "clubs", "diamonds"];

  function pickCard(x: number | object[]): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card
    if (typeof x == "object") {
      let pickedCard = Math.floor(Math.random() * x.length);
      return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == "number") {
      let pickedSuit = Math.floor(x / 13);
      return { suit: suits[pickedSuit], card: x % 13 };
    }
  }

  let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
  let pickedCard1 = myDeck[pickCard(myDeck)];
  console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

  let pickedCard2 = pickCard(15);
  console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
}

function function_eg04_new() {
  let suits = ["hearts", "spades", "clubs", "diamonds"];

  function pickCard(x: { suit: string; card: number; }[]): number;
  function pickCard(x: number): { suit: string; card: number; };

  function pickCard(x: any): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card
    if (typeof x == "object") {
      let pickedCard = Math.floor(Math.random() * x.length);
      return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == "number") {
      let pickedSuit = Math.floor(x / 13);
      return { suit: suits[pickedSuit], card: x % 13 };
    }
  }

  let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
  let pickedCard1 = myDeck[pickCard(myDeck)];
  console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

  let pickedCard2 = pickCard(15);
  console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
}

// 执行
function_eg04_new()